home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / nasanets.zip / PAIRS.C < prev    next >
C/C++ Source or Header  |  1990-06-07  |  35KB  |  961 lines

  1. /*=============================*/
  2. /*           NETS              */
  3. /*                             */
  4. /* a product of the AI Section */
  5. /* NASA, Johnson Space Center  */
  6. /*                             */
  7. /* principal author:           */
  8. /*       Paul Baffes           */
  9. /*                             */
  10. /* contributing authors:       */
  11. /*      Bryan Dulock           */
  12. /*      Chris Ortiz            */
  13. /*=============================*/
  14.  
  15.  
  16. /*
  17. ----------------------------------------------------------------------
  18.   Code For Setting up IO pairs for Network training (Prefix = PA_)
  19. ----------------------------------------------------------------------
  20.   This code is divided into 4 major sections:
  21.  
  22.   (1) include files
  23.   (2) externed functions
  24.   (3) global variables
  25.   (4) subroutines
  26.  
  27.   Each section is further explained below.
  28. ----------------------------------------------------------------------
  29. */
  30.  
  31.  
  32. /*
  33. ----------------------------------------------------------------------
  34.   INCLUDE FILES
  35. ----------------------------------------------------------------------
  36. */
  37. #include "common.h"
  38. #include "weights.h"
  39. #include "layer.h"
  40. #include "net.h"
  41. #include "netio.h"
  42.  
  43.  
  44. /*
  45. ----------------------------------------------------------------------
  46.   EXTERNED FUNCTIONS
  47. ----------------------------------------------------------------------
  48.   Below are the functions defined in other files which are used by the
  49.   code here. They are organized by section.
  50. ----------------------------------------------------------------------
  51. */
  52. extern int    PS_parse_iopairs();
  53. extern float  C_Sint_to_float();
  54. extern char   *sys_long_alloc();
  55. extern char   *sys_alloc();
  56. extern void   sys_long_free();
  57. extern void   sys_free();
  58. extern void   sys_delete_file();
  59. extern void   sys_rename_file();
  60. extern long   IO_find_file_size();
  61. extern void   IO_print();
  62.  
  63. extern char   IO_str[MAX_LINE_SIZE];
  64.  
  65.  
  66.  
  67. /*
  68. ----------------------------------------------------------------------
  69.   GLOBAL VARIABLES
  70. ----------------------------------------------------------------------
  71.   Next come the global variables for this code.  All of them revolve
  72.   around reading information from files. In order to speed things up,
  73.   I buffer the input and do block reads into a large space in an array
  74.   from which all other routines work (see documentation in 'netio.h').
  75.   The 'fd_iofile' is an integer which is used as a file descriptor to 
  76.   keep track of the INTERMEDIATE file which is created during training. 
  77.   An intermediate file of IO pairs is created to facilitate training 
  78.   speeds. These pairs are block read into the buffer (ie, "the_buffer" 
  79.   below) and then referenced from there. 
  80. ----------------------------------------------------------------------
  81. */
  82. static buffer  *the_buffer;      /* global here but not visible outside */
  83.  
  84. static FILE    *fp_iofile = NULL;/* used by rewind_workfile to close    */
  85.                                  /* and reopen the file which has the   */
  86.                                  /* IO pairs for teaching the net.      */
  87.  
  88.  
  89. /*
  90. ======================================================================
  91.   ROUTINES IN PAIRS.C                                                   
  92. ======================================================================
  93.   The routines in this file are grouped below by function.  Each routine
  94.   is prefixed by the string "PA_" indicating that it is defined in the 
  95.   "pairs.c" file.  The types returned by the routines are also shown here
  96.   so that cross checking is more easily done between these functions
  97.   and the other files which intern them.
  98.  
  99.  
  100.   Type Returned                 Routine                                 
  101.   -------------                 -------                                 
  102.     void                        PA_initialize                            
  103.     void                        PA_setup_iopairs                            
  104.     void                        PA_reset_iopairs                            
  105.     FILE *                      PA_open_binary
  106.     void                        PA_write_signature
  107.     int                         PA_check_signature
  108.     int                         PA_put_to_workfile
  109.     void                        PA_flush
  110.     void                        PA_rewind_workfile
  111.     void                        PA_done_with_workfile
  112.     Sint                        PA_retrieve
  113.     int                         PA_get_from_workfile (returns Sint via args)
  114.     void                        PA_randomize_file
  115.     void                        PA_build_random_list
  116.     void                        PA_transfer_blocks
  117.     void                        PA_write_iop
  118.     void                        PA_put_ascii_wts
  119.     Sint                         PA_get_ascii_wts
  120. ======================================================================
  121. */
  122.  
  123.  
  124. void  PA_initialize()
  125. /*
  126. ----------------------------------------------------------------------
  127.  Because the buffer used for reading and writing Sint values from     
  128.   temporary files is NOT VISIBLE outside of this code, this init      
  129.   routine is provided to make sure that space is actually set asside  
  130.   for the buffer.                                    
  131. ----------------------------------------------------------------------
  132. */
  133. BEGIN
  134.    the_buffer = (buffer *) sys_alloc((unsigned)sizeof(buffer));
  135.    the_buffer->index = BUFFER_SIZE;
  136.    the_buffer->last_elem = -1;       /* no elements in buffer */
  137.    
  138. END /* PA_initialize */
  139.  
  140.  
  141. void  PA_setup_iopairs(ptr_net, filename)
  142. Net   *ptr_net;
  143. char  filename[];
  144. /*
  145. ----------------------------------------------------------------------
  146.  This routine actually does very little of the work involved with     
  147.   setting up the io pairs.  Instead, most of the work is passed to an 
  148.   IO routine (in netio.c) since so much of io is machine dependent.   
  149.   (That is, our netio.c was created specifically to isolate any code  
  150.   dependent on I/O).                                                  
  151.  All this routine does is setup determine what the expected lenght of 
  152.   the io-pairs should be (from the sizes of the input and output      
  153.   layers) and then pass the work on to the IO routines.  The result   
  154.   returned indicates how many io pairs were specified in the input    
  155.   file, or an ERROR indicating some sort of error in the input file.    
  156. ----------------------------------------------------------------------
  157. */
  158. BEGIN
  159.    int  sum;
  160.    
  161.    ptr_net->num_inputs  = ptr_net->input_layer->num_nodes;
  162.    ptr_net->num_outputs = ptr_net->output_layer->num_nodes;
  163.  
  164.    sum = ptr_net->num_inputs + ptr_net->num_outputs;
  165.    ptr_net->num_io_pairs = PS_parse_iopairs(filename, sum);
  166.  
  167.    if (ptr_net->num_io_pairs == ERROR)
  168.       sprintf(IO_str, "\n*** problems with IO pairs specification ***\n");
  169.    else
  170.       sprintf(IO_str, "\n %d IO pairs read\n", ptr_net->num_io_pairs);
  171.    IO_print(0);
  172.  
  173. END /* PA_setup_iopairs */
  174.  
  175.  
  176. void  PA_reset_iopairs(ptr_net, bin_filename)
  177. Net  *ptr_net;
  178. char  bin_filename[];
  179. /*
  180. ----------------------------------------------------------------------
  181.   This routine resets the values in the ptr_net Net structure to match
  182.   the number of iopairs found in the "filename" binary file. Several
  183.   assumptions are made. First, it is assumed that the incoming filename
  184.   indicates a binary file which was created at some earlier time by a
  185.   call to the "i" option of NETS (recall that the "i" option has the
  186.   effect of translating an ascii IOP file into a binary Sint format).
  187.   This file's length is determined and compared against the number of
  188.   inputs and outputs to determine the amount of iopairs in the file.
  189.   If the sizes do not map evenly, then this routine fails.
  190. ----------------------------------------------------------------------
  191. */
  192. BEGIN
  193.    int  in_size, out_size, pair_size, file_len, num_iopairs;
  194.  
  195.    /*---------------------------------------*/
  196.    /* get the sizes of the input and output */
  197.    /* layers and the size of the file. NOTE */
  198.    /* the size of one iopair must be multi- */
  199.    /* plied by the size of a Sint in bytes. */
  200.    /*---------------------------------------*/
  201.    in_size   = ptr_net->input_layer->num_nodes;
  202.    out_size  = ptr_net->output_layer->num_nodes;
  203.    pair_size = sizeof(Sint) * (in_size + out_size);
  204.    file_len  = IO_find_file_size(bin_filename);
  205.    
  206.    /*--------------------------------------*/
  207.    /* determine how many iopairs could fit */
  208.    /* in file. NOTE that "/" rounds down   */
  209.    /*--------------------------------------*/
  210.    num_iopairs = file_len / pair_size;
  211.    
  212.    /*------------------------------------------*/
  213.    /* remultiplying the number of pairs by the */
  214.    /* sum of the input and output sizes should */
  215.    /* yield the file size if there is a match  */
  216.    /*------------------------------------------*/
  217.    if ( (num_iopairs * pair_size) != file_len )
  218.       sprintf(IO_str, "\n*** net configuration does not match '%s' file ***\n", bin_filename);
  219.    else BEGIN
  220.       ptr_net->num_inputs   = in_size;
  221.       ptr_net->num_outputs  = out_size;
  222.       ptr_net->num_io_pairs = num_iopairs;
  223.       sprintf(IO_str, "\n %d IO pairs read\n", num_iopairs);
  224.    ENDELSE
  225.    IO_print(0);
  226.  
  227. END /* PA_reset_iopairs */
  228.  
  229.  
  230. FILE  *PA_open_binary(file_name, mode)
  231. char  file_name[];
  232. int   mode;
  233. /*
  234. ----------------------------------------------------------------------
  235.  Resets the file given in "file name" using the open call with the    
  236.   mode specified by "mode".  Note, this will only reset for mass IO   
  237.   reading and writing, and it also assumes the existence of a buffer  
  238.   for holding all of the IO.  The result returned is a file pointer
  239.   which can then be used for reading from or writing to the file.     
  240.  NOTE THAT THE CALLER MUST ENSURE THAT THE FILE IS CLOSED.            
  241. ----------------------------------------------------------------------
  242. */
  243. BEGIN
  244.    FILE  *fp;
  245.  
  246.    if (mode == READ_MODE) BEGIN
  247.       fp = fopen(file_name, "rb");
  248.       the_buffer->index = BUFFER_SIZE;
  249.       the_buffer->last_elem = -1;      /* no elements in buffer */
  250.    ENDIF
  251.    else BEGIN
  252.       fp = fopen(file_name, "wb");
  253.       the_buffer->index = 0;
  254.    ENDELSE
  255.    return(fp);
  256.  
  257. END /* PA_open_binary */
  258.  
  259.  
  260. void  PA_write_signature(fp, signature)
  261. FILE       *fp;
  262. short int  signature;
  263. /*
  264. ----------------------------------------------------------------------
  265.   Writes out the 2-byte signature to the file indicated by "fp."  Note
  266.   that only 2 bytes are written, regardless of whether Sint or float
  267.   format is being used.
  268. ----------------------------------------------------------------------
  269. */
  270. BEGIN
  271.  
  272.    /*-----------------------------------------*/
  273.    /* the "2" indicates that the signature is */
  274.    /* 2-bytes long. "1" means 1 sig written   */
  275.    /*-----------------------------------------*/
  276.    fwrite((char *)(&signature), SIG_SIZE, 1, fp);
  277.  
  278. END /* PA_write_signature */
  279.  
  280.  
  281. int  PA_check_signature(filename, format)
  282. char  filename[];
  283. int   format;
  284. /*
  285. ----------------------------------------------------------------------
  286.   This routine opens the file "filename" and checks the first two bytes
  287.   of the file to determine whether or not the file has a signature. IF
  288.   it does, it will have the BIN_SIG of all binary weights files used by 
  289.   NETS. The format of the file must match the format passed in by the 
  290.   "format" parameter. If there is no match or if the file cannot be 
  291.   opened, then an error is returned.
  292. ----------------------------------------------------------------------
  293. */
  294. BEGIN
  295.    FILE       *fp;
  296.    short int  signature;
  297.    int        PA_text_sig_check();
  298.    
  299.    /*--------------------------------------------*/
  300.    /* if the file cannot be opened, return error */
  301.    /*--------------------------------------------*/
  302.    if ( (fp = fopen(filename, "rb")) == NULL ) BEGIN
  303.       sprintf(IO_str, "\n*** can't open file %s ***\n", filename);
  304.       IO_print(0);
  305.       return(ERROR);
  306.    ENDIF
  307.    
  308.    /*------------------------------------*/
  309.    /* otherwize, read in the signature   */
  310.    /* NOTE signatures are always 2 bytes */
  311.    /*------------------------------------*/
  312.    fread((char *)(&signature), SIG_SIZE, 1, fp);
  313.    fclose(fp);
  314.    
  315.    /*-------------------------------------*/
  316.    /* first check the desired file format */
  317.    /*-------------------------------------*/
  318.    if (format == FAST_FORMAT) BEGIN
  319.    
  320.       /*--------------------------------*/
  321.       /* if signature is correct return */
  322.       /*--------------------------------*/
  323.       if (signature == BIN_SIG) return(OK);
  324.       
  325.       /*------------------------------------------------*/
  326.       /* otherwise, signature could be binary but wrong */
  327.       /*------------------------------------------------*/
  328.       if (signature == WRONG_SIG) BEGIN
  329.          sprintf(IO_str, "\n*** file is not in %s format",
  330.                  ((USE_SCALED_INTS == 1)? "scaled integer" : "floating point") );
  331.          IO_print(0);
  332.       ENDIF
  333.       
  334.       /*------------------------------------------------*/
  335.       /* or, lastly, signature might not even be binary */
  336.       /*------------------------------------------------*/
  337.       else BEGIN
  338.          sprintf(IO_str, "\n*** file is not in FAST format");
  339.          IO_print(0);
  340.       ENDELSE
  341.       
  342.       /*----------------------------------*/
  343.       /* in any case, if you get past the */
  344.       /* BIN_SIG case you return an error */
  345.       /*----------------------------------*/
  346.       return(ERROR);
  347.    ENDIF
  348.    
  349.    /*-----------------------------------*/
  350.    /* else if format is PORTABLE_FORMAT */
  351.    /*-----------------------------------*/
  352.    else BEGIN
  353.       if ((signature == BIN_SIG) || (signature == WRONG_SIG)) BEGIN
  354.         sprintf(IO_str, "\n*** file not in PORTABLE format");
  355.         IO_print(0);
  356.         return(ERROR);
  357.       ENDIF
  358.       else 
  359.          return(PA_text_sig_check(filename));
  360.    ENDELSE
  361.    
  362. END /* PA_check_signature */
  363.  
  364.  
  365. int  PA_text_sig_check(filename)
  366. char  filename[];
  367. /*
  368. ----------------------------------------------------------------------
  369.   This routine checks PORTABLE format files only. The problem here is
  370.   that if a file is written in ascii it cannot be given an initial 
  371.   signature like a binary file can. Thus, the PA_check_signature routine
  372.   must call this routine in the event that a portable file is successfully
  373.   found. This routine returns OK or ERROR, depending upon whether or not
  374.   the data in the file matches the Sint format (when USE_SCALED_INTS = 1)
  375.   or the float format.
  376. ----------------------------------------------------------------------
  377. */
  378. BEGIN
  379.    FILE  *fp;
  380.    char  in_str[MAX_WORD_SIZE];
  381.    int   i, float_present = FALSE;
  382.    
  383.    /*------------------------------------*/
  384.    /* get the first string from the file */
  385.    /*------------------------------------*/
  386.    fp = fopen(filename, "rt");
  387.    fgets(in_str, MAX_WORD_SIZE, fp);
  388.    fclose(fp);
  389.    
  390.    /*-----------------------------*/
  391.    /* try to find a decimal point */
  392.    /*-----------------------------*/
  393.    i = 0;
  394.    while (in_str[i] != '\0') BEGIN
  395.       if (in_str[i] == '.') BEGIN
  396.          float_present = TRUE;
  397.          break;
  398.       ENDIF
  399.       i++;
  400.    ENDWHILE
  401.    
  402.    /*----------------------------*/
  403.    /* if formats match return OK */
  404.    /*----------------------------*/
  405.    if ( ((float_present == FALSE) && (USE_SCALED_INTS == 1))
  406.         || ((float_present == TRUE) && (USE_SCALED_INTS == 0)) )
  407.       return(OK);
  408.    
  409.    /*------------------------------------------------*/
  410.    /* otherwise, printout error msg and return ERROR */
  411.    /*------------------------------------------------*/
  412.    sprintf(IO_str, "\n*** file is not in %s format",
  413.            ((USE_SCALED_INTS == 1) ? "scaled integer" : "floating point") );
  414.    IO_print(0);
  415.    return(ERROR);
  416.       
  417. END /* PA_text_sig_check */
  418.  
  419.  
  420. int  PA_put_to_workfile(fp, Snum)
  421. FILE  *fp;
  422. Sint  Snum;
  423. /*
  424. ----------------------------------------------------------------------
  425.  This routine puts out Sints to a temporary storage file for the net. 
  426.   By default, I have decided to call the file "workfile.net" as it is 
  427.   named in the above routine 'PS_parse_iopairs'.  Instead of putting   
  428.   out Sints a word at a time, this routine first writes the Sint to a 
  429.   buffer and then checks to see if the buffer is full. If so, then the
  430.   entire buffer is mass written to the temporary file, which is much  
  431.   quicker than trying to do things a word at a time.                  
  432.  
  433.  Returns OK if the write goes ok, otherwise returns ERROR.
  434. ----------------------------------------------------------------------
  435. */
  436. BEGIN
  437.    int  temp;
  438.  
  439.    temp = OK;
  440.    if (the_buffer->index >= BUFFER_SIZE) BEGIN /* the buffer is full    */
  441.       temp = fwrite((char *)the_buffer->values, sizeof(Sint), BUFFER_SIZE, fp);
  442.       if (temp != BUFFER_SIZE) BEGIN
  443.          sprintf(IO_str, "\n*** Internal Error writing to WorkFile ***\n");
  444.          IO_print(0);
  445.          temp = ERROR;
  446.       ENDIF
  447.       else temp = OK;
  448.       the_buffer->index = 0;
  449.    ENDIF
  450.  
  451.    the_buffer->values[the_buffer->index] = Snum;
  452.    the_buffer->index++;
  453.    return(temp);
  454.  
  455. END /* PA_put_to_workfile */
  456.  
  457.  
  458. void  PA_flush(fp)
  459. FILE  *fp;
  460. /*
  461. ----------------------------------------------------------------------
  462.  This guy will print whatever is left in the buffer out to the temp   
  463.   file.  That is, after the last character is "put" by the routine    
  464.   above, there is no guarantee that the buffer was also printed to the
  465.   (in fact, it would have only been printed in the case that the last 
  466.   "put" exactly filled the buffer).  So this routine is needed to make
  467.   sure that nothing gets lost in the buffer.                          
  468. ----------------------------------------------------------------------
  469. */
  470. BEGIN
  471.    fwrite((char *)the_buffer->values, sizeof(Sint), the_buffer->index, fp);
  472.    the_buffer->index = 0;
  473.  
  474. END /* PA_flush */
  475.  
  476.  
  477. void  PA_rewind_workfile()
  478. /*
  479. ----------------------------------------------------------------------
  480.  This routine resets the temporary file ("workfile.net") which has    
  481.   all of the io pairs by opening or rewinding the file.  This   
  482.   must be done EACH TIME through a learning cycle.  Also, the input   
  483.   buffer ('the_buffer') must be reset to indicate that new values are 
  484.   to be read in.  This is done by setting the index of the buffer to
  485.   BUFFER_SIZE.
  486. ----------------------------------------------------------------------
  487. */
  488. BEGIN
  489.    if (fp_iofile == NULL)
  490.       fp_iofile = fopen("workfile.net", "rb");
  491.    else if (fseek(fp_iofile, 0L, SEEK_SET) != 0) BEGIN
  492.       sprintf(IO_str, "\n*** INTERNAL ERROR: could not rewind WorkFile");
  493.       IO_print(0);
  494.    ENDELSE
  495.  
  496.    /*----------------------------------------------*/
  497.    /* index set to end to force a read of the file */
  498.    /*----------------------------------------------*/
  499.    the_buffer->index = BUFFER_SIZE;
  500.    the_buffer->last_elem = -1;
  501.  
  502. END /* PA_rewind_workfile */
  503.  
  504.  
  505. void  PA_done_with_workfile()
  506. /*
  507. ----------------------------------------------------------------------
  508.   This routine makes sure that the "workfile.net" file is closed before
  509.   training is completed. It is only called by "T_teach_net" routine.
  510. ----------------------------------------------------------------------
  511. */
  512. BEGIN   
  513.    if (fp_iofile != NULL) fclose(fp_iofile);
  514.    fp_iofile = NULL;
  515.  
  516. END  /* PA_done_with_workfile */
  517.  
  518.  
  519. Sint  PA_retrieve()
  520. /*
  521. ----------------------------------------------------------------------
  522.  This may seem like an absolutely stupid routine, and on one level I  
  523.   agree; it is so small it seems ridiculous to waste time doing a     
  524.   routine call just to set up another routine call.  However, I wanted
  525.   to leave the 'PA_get_from_workfile', or 'get', routine isolated, so that
  526.   it could be used for different kinds of IO.  For example, if I had     
  527.   simply called the 'get' routine directly from 'net.c', then it would
  528.   have had to assume the existence of the file descriptor 'fp_iofile' 
  529.   just as this routine does.  Of course, then the 'get' routine would 
  530.   only be good for reading from that file descriptor, which is really 
  531.   not a good limitation, nor would it be consistent with the routine  
  532.   'put_to_workfile'.  Thus this routine acts as a sort of filter to   
  533.   any outside routines from other files from having to know any of the
  534.   details of the IO.                                                  
  535.  Note that this routine assumes the existence of a global file des-   
  536.   criptor called 'fd_iofile' which points to the work file.           
  537.  Returns positive or 0 if the read goes ok, otherwise returns a -1.   
  538. ----------------------------------------------------------------------
  539. */
  540. BEGIN
  541.    int   PA_get_from_workfile();
  542.    Sint  result;
  543.  
  544.    if (PA_get_from_workfile(fp_iofile, &result) == ERROR) BEGIN
  545.       sprintf(IO_str, "\n*** INTERNAL ERROR: could not access WorkFile");
  546.       IO_print(0);
  547.    ENDIF
  548.    return(result);
  549.  
  550. END /* PA_retrieve */
  551.  
  552.  
  553. int  PA_get_from_workfile(fp, ptr_Sint)
  554. FILE  *fp;
  555. Sint  *ptr_Sint;
  556. /*
  557. ----------------------------------------------------------------------
  558.  This routine is the converse of 'put_to_workfile' above.  Instead of 
  559.   storing Sints, it reads them out of memory and places them into the 
  560.   'ptr_Sint' variable passed in.  Again, the default file for reading 
  561.   is the same one where the stuff was written; "workfile.net".        
  562.  Returns OK if a value can be read, ERROR otherwise.
  563. ----------------------------------------------------------------------
  564. */
  565. BEGIN
  566.    int  temp;
  567.  
  568.    temp = OK;
  569.    /*----------------------------------*/ 
  570.    /* if the buffer contents exhausted */
  571.    /* try reading more from file       */
  572.    /*----------------------------------*/ 
  573.    if (the_buffer->index >= BUFFER_SIZE) BEGIN
  574.       temp = fread((char *)the_buffer->values, sizeof(Sint), BUFFER_SIZE, fp);
  575.       if (temp == 0) BEGIN
  576.          sprintf(IO_str, "\n*** Internal Error reading from file ***\n");
  577.          IO_print(0);
  578.          temp = ERROR;
  579.       ENDIF
  580.       else BEGIN
  581.          the_buffer->last_elem = temp - 1;
  582.          temp = OK;
  583.          the_buffer->index = 0;
  584.       ENDELSE
  585.    ENDIF
  586.    /*----------------------------------------*/
  587.    /* otherwise, if already read past end of */
  588.    /* buffer then return error and message   */
  589.    /*----------------------------------------*/
  590.    else if (the_buffer->index > the_buffer->last_elem) BEGIN
  591.       temp = ERROR;
  592.       sprintf(IO_str, "\n*** attempt to read past last value of file");
  593.       IO_print(0);
  594.    ENDELSE
  595.    
  596.    /*----------------------------------*/
  597.    /* in any event, read the next elem */
  598.    /*----------------------------------*/
  599.    *ptr_Sint = the_buffer->values[the_buffer->index];
  600.    the_buffer->index++;
  601.    
  602.    return(temp);
  603.  
  604. END /* PA_get_from_workfile */
  605.  
  606.  
  607. void  PA_randomize_file(new_file, bin_file, num_blocks, block_size)
  608. char  *new_file, *bin_file;
  609. int   num_blocks, block_size;
  610. /*
  611. ----------------------------------------------------------------------
  612.    RANDOMIZE_FILE will take a binary file of I/O pairs and rearrange 
  613.                   the I/O pairs in a random order.
  614.                   
  615.    Author : Chris Ortiz ( MPAD/AI NASA )
  616.    Date   : 31-May-1989
  617.    Cyclomatic Complexity = 1
  618.    
  619.    Parameters Used
  620.    ---------------
  621.       Num_Blocks - The number of I/O pairs ( Blocks ) in the binary file.
  622.       Block_Size - The number of bytes in each I/O pair.
  623.       File_Name  - Binary file to be sorted.
  624.  
  625.    Variables Used
  626.    --------------
  627.       Array      - Array with the random order for the binary blocks.
  628.      
  629.    Procedures / Functions
  630.    ----------------------
  631.    
  632.       PA_build_random_list - will take an array, initialize it, and
  633.           select and store a group of random block numbers.
  634.       PA_transfer_blocks - will take an array and build a new file
  635.           using random blocks from the old file.
  636.  
  637.    Algorithm
  638.    ---------
  639.       1. Build array of random numbers corresponding to random I/O pairs.
  640.       2. Build I/O pair file in random order corresponding to the array.
  641.  
  642. ----------------------------------------------------------------------
  643. */
  644. BEGIN
  645.    int   *array;
  646.    void  PA_build_random_list(), PA_transfer_blocks();
  647.    
  648.    array = (int *) sys_alloc((unsigned)num_blocks * (unsigned)sizeof(int));
  649.    num_blocks = num_blocks - 1;    /* Number of Blocks must start at 0 */
  650.    PA_build_random_list(array, num_blocks);
  651.    PA_transfer_blocks(array, new_file, bin_file, block_size, num_blocks);
  652.    
  653.    sys_free((char *) array);
  654.    
  655. END /* PA_randomize_file */
  656.  
  657.  
  658. void  PA_build_random_list(array, num_block)
  659. int   array[], num_block;
  660. /*
  661. ----------------------------------------------------------------------
  662.   BUILD_RANDOM_LIST will take an array, select non-repeating random numbers
  663.                        from 0 to sizeof(array), and store the numbers back into
  664.                        the array for use later.
  665.                  
  666.   Author : Chris Ortiz ( MPAD/AI NASA )
  667.   Date   : 1-Jun-1989
  668.   Cyclomatic Complexity = 3
  669.  
  670.   Parameters Used
  671.   ---------------
  672.      Array - Array containing the random order of block Id's. (Output)
  673.      Num_Block - Number of blocks in a file. (Input)
  674.  
  675.   Variables Used
  676.   --------------
  677.      Last - Pointer to tail of array.
  678.      Slot - Random Slot in array.
  679.      Temp - Storage Variable
  680.      
  681.   Procedures / Functions
  682.   ----------------------
  683.      Rand() - Returns a pseudorandom-number 0..32,767 ( RAND_MAX ).
  684.  
  685.   Algorithm
  686.   ---------
  687.      1. Initialize array with numbers corresponding to the index.
  688.      2. Initialize the random number generator.
  689.      3. Pick a random index into the array from 0 to the last known element.
  690.      4. Swap contents with the last known element in the array
  691.      5. Move last known element up one index and goto step 3.
  692. ----------------------------------------------------------------------
  693. */
  694. BEGIN
  695.    int last, slot, temp;
  696.  
  697.    for (last =0; last <= num_block; last++)
  698.        array[last] = last;
  699.  
  700.    for (last = num_block; last > 0; last--) BEGIN
  701.        slot = rand() % last;
  702.        temp = array [slot];
  703.        array[slot] = array[last];
  704.        array[last] = temp;
  705.    ENDFOR
  706.    
  707. END /* PA_build_random_list */
  708.  
  709.  
  710. void  PA_transfer_blocks (array, new_file, bin_file, block_size, num_blocks)
  711. int   array[];
  712. char  *new_file, *bin_file;
  713. int   block_size, num_blocks;
  714. /*
  715. ----------------------------------------------------------------------
  716.   TRANSFER_BLOCKS will transfer a block of data from one file to a
  717.                    new file in a specified order which is contained
  718.                      in the array argument.
  719.                  
  720.   Author : Chris Ortiz ( MPAD/AI NASA )
  721.   Date   : 2-Jun-1989
  722.   Cyclomatic Complexity = 2
  723.  
  724.   Parameters Used
  725.   ---------------
  726.      Array       - Array containing the random order of block Id's.
  727.      File_Name   - Binary File (Unsorted) Name
  728.      Block_Size  - Number of bytes per block of data.
  729.      Num_Block   - Number of blocks in a file.
  730.   
  731.   Variables Used
  732.   --------------
  733.      FP_Output   - Output File
  734.      FP_Input    - Input File
  735.      Ptr         - Element of file to be transfered
  736.      Block       - Current Block Number
  737.      Byte_Offset - Number of Bytes into file before reading.
  738.      
  739.   Procedures / Functions
  740.   ----------------------
  741.      Write_IOP   - Write a single I/O pair into an ascii format.
  742.  
  743.   Algorithm
  744.   ---------
  745.      1. Open Files.
  746.      2. Read Array to get next random block to read.
  747.      3. Jump into input file to the random Block. (Byte_offset)
  748.      4. Read Block from input and write to output (Ascii and Binary).
  749.      5. If not done with random blocks goto step 2.
  750.      6. Close Files
  751.      7. Delete input file ( non-random ).
  752.      8. Rename output file to the name used for the input file.
  753. ----------------------------------------------------------------------
  754. */
  755. BEGIN
  756.    long int byte_offset;
  757.    int    block;
  758.    FILE  *fp_input, *fp_output, *fp_ascii;
  759.    void  PA_write_iop();
  760.    Sint  *ptr;
  761.    
  762.    ptr = (Sint *) sys_long_alloc((long)(block_size * sizeof(Sint)));
  763.    
  764.    fp_input  = fopen(bin_file, "rb");
  765.    fp_output = fopen("workfile.rnd", "wb");
  766.    fp_ascii  = fopen(new_file,"wt");
  767.    
  768.    for (block = 0; block <= num_blocks; block++) BEGIN
  769.       byte_offset =  (long)(array[block] * block_size * sizeof(Sint));
  770.       fseek(fp_input, byte_offset, SEEK_SET);
  771.       
  772.       fread((char *)ptr, sizeof(Sint), block_size, fp_input);
  773.       PA_write_iop(ptr, block_size, fp_ascii);
  774.       fwrite((char *)ptr, sizeof(Sint), block_size, fp_output);
  775.    ENDFOR
  776.  
  777.    fclose(fp_input);
  778.    fclose(fp_ascii);
  779.    fclose(fp_output);
  780.  
  781.    sys_delete_file(bin_file);
  782.    sys_rename_file("workfile.rnd", bin_file);
  783.   
  784.    sys_long_free((char *) ptr);
  785.    
  786. END /* PA_transfer_blocks */
  787.  
  788.  
  789. void  PA_write_iop (ptr, num_ptr, fp_ascii)
  790. Sint  *ptr;
  791. int   num_ptr;
  792. FILE  *fp_ascii;
  793. /*
  794. ----------------------------------------------------------------------
  795.   PA_WRITE_IOP will write the ascii version for the random I/O pairs to a file.
  796.                  
  797.   Author : Chris Ortiz ( MPAD/AI NASA )
  798.   Date   : 3-Jun-1989
  799.   Cyclomatic Complexity = 3
  800.  
  801.   Parameters Used
  802.   ---------------
  803.      Ptr        - Array containing one I/O pairs to be sent to the ascii file.
  804.      Num_Ptr    - Size of Array.
  805.      Fp_Ascii   - Ascii file where I/O pairs are to be written.
  806.  
  807.   Variables Used
  808.   --------------
  809.      N_Row      - number of fields to be printed on one line.
  810.      byte       - loop counter.
  811.      
  812.   Procedures / Functions
  813.   ----------------------
  814.      C_Sint_to_float - converts type SINT to type float.
  815.  
  816.   Algorithm
  817.   ---------
  818.      1. Write '(' to ascii file.
  819.      2. Write convert SINT to float and write to file.
  820.      3. Write only N_Row number of floats to a line.
  821.      4. Write ')' to finish I/O pair.
  822. ----------------------------------------------------------------------
  823. */
  824. BEGIN
  825.    int  n_row, byte;
  826.    
  827.    n_row = 3;
  828.    fprintf (fp_ascii,"(");
  829.          
  830.    for (byte=1; byte <= num_ptr ; byte++) BEGIN
  831. #if  USE_SCALED_INTS
  832.       fprintf (fp_ascii, "%7.3f", C_Sint_to_float(ptr[byte - 1]));
  833. #else
  834.       fprintf (fp_ascii, " %f", ptr[byte - 1]);
  835. #endif
  836.  
  837.       /*----------------------------------------------*/
  838.       /* after each sint is printed, check to see if  */
  839.       /* you have printed "n_row" of them. If so,     */
  840.       /* then print a newline. Note that byte starts  */
  841.       /* at "1" (not 0) because of the comparisons    */
  842.       /* done here. If it started at 0, you would     */
  843.       /* printout a newline after the first element   */
  844.       /* (try it). Of course, you could equally as    */
  845.       /* well start at "0" and do comparisons here at */
  846.       /* byte+1, but that would mean two additions    */
  847.       /* here, so I opted for byte starting at "1".   */
  848.       /* Finally, note that this means byte must be   */
  849.       /* decremented by one to be written out to file */
  850.       /*----------------------------------------------*/
  851.       if ((byte % n_row == 0) && (byte < num_ptr))
  852.          fprintf(fp_ascii,"\n");
  853.          
  854.    ENDFOR
  855.    fprintf (fp_ascii," )\n");
  856.    
  857. END /* PA_write_iop */
  858.  
  859.  
  860. Sint  PA_get_ascii_wts(fp, weight)
  861. FILE  *fp;
  862. Sint  *weight;
  863. /*
  864. --------------------------------------------------------------------------------
  865.  
  866.  PA_GET_ASCII_WTS will return a single Sint weight from an ASCII file format.
  867.  
  868.  Author : Chris Ortiz ( MPAD/AI NASA )
  869.  Date   : 4-Aug-1989
  870.  Cyclomatic Complexity = 2
  871.  
  872.  Variables Used
  873.  --------------
  874.       fp      - File pointer to ASCII file.
  875.       weight  - Parameter the weight is sent to.
  876.       line    - Line of characters from the input file.
  877.       tmp     - Error condition that is returned from this procedure.
  878.  
  879.   Algorithm
  880.   ---------
  881.       1. Read a line of characters from input file.
  882.       2. Convert characters to floating point number. (One Float per line)
  883.       3. Convert floating point number to type Sint and store in return var.
  884.       4. Return the error condition.
  885.  
  886.   Modified (8-15-89) to read in integer representations of the Sints rather
  887.   than floating point representations. The rationale here is that saving floating
  888.   point numbers does nothing except cause rounding errors. The user does not really
  889.   need to be able to read the numbers in their floating point format since there 
  890.   is no additional information in the file which indicates what nodes are attached
  891.   to the weight. Thus, since the floating point conversion can cause round off
  892.   errors, I decided to switch to saving the Sints in ascii (but integer) format.
  893. -----------------------------------------------------------------------------------
  894. */
  895. BEGIN
  896.    char line[MAX_LINE_SIZE];
  897.    int  tmp;
  898. #if  USE_SCALED_INTS
  899.    int  val;
  900. #else
  901.    float  val;
  902. #endif
  903.    
  904.    tmp = ERROR;
  905.    
  906.    if ( !feof(fp) ) BEGIN
  907.       fgets(line, MAX_LINE_SIZE, fp);
  908. #if  USE_SCALED_INTS
  909.       if (sscanf(line, "%d", &val) == 1) BEGIN
  910. #else
  911.       if (sscanf(line, "%f", &val) == 1) BEGIN
  912. #endif
  913.          *weight = (Sint) val;
  914.          tmp = OK;
  915.       ENDIF
  916.    ENDIF
  917.    return(tmp);
  918.    
  919. END /* PA_get_ascii_wts */
  920.  
  921.  
  922. void  PA_put_ascii_wts(weights, num_weights, fp)
  923. Sint  *weights;
  924. int32 num_weights;
  925. FILE  *fp;
  926. /*
  927. -------------------------------------------------------------------------------
  928.  
  929.  PA_PUT_ASCII_WTS will write an array of ASCII weights to a file.
  930.  
  931.  Author : Chris Ortiz ( MPAD/AI NASA )
  932.  Date   : 4-Aug-1989
  933.  Cyclomatic Complexity = 2
  934.  
  935.  Variables Used
  936.  --------------
  937.       fp          - File pointer to ASCII file.
  938.       weights     - array of weights to be written to a file.
  939.       num_weights - number of weights in the array.
  940.       loop        - variable user to index array.
  941.  
  942.  Algorithm
  943.  ---------
  944.       For each location in the weights array
  945.       1. convert from SINT to floating point.
  946.       2. write floating point number on a single line to the output file.
  947.  
  948. ---------------------------------------------------------------------------------
  949. */
  950. BEGIN
  951.    int32 loop;
  952.    
  953.    for ( loop=0; loop < num_weights ; loop++ )
  954. #if  USE_SCALED_INTS
  955.       fprintf(fp, "%d\n", (int)(weights[loop]) );
  956. #else
  957.       fprintf(fp, "%f\n", (float)(weights[loop]) );
  958. #endif
  959.  
  960. END /* PA_put_ascii_wts */
  961.